package com.catena.core.chain;

import com.catena.core.NodeParameter;
import com.catena.core.NotFoundMehtodOfClass;
import com.catena.core.node.CatenaNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.BlockingQueue;

/**
 * Created by hx-pc on 16-3-3.
 */
public class NodeOperationNormal extends CatenaOperationNodeAppender implements CatenaOperationNodeExecute {

    private static final Logger LOGGER = LoggerFactory.getLogger("nodeStatus");

    /**
     * 主要执行方法,根据传入的方法名来执行对应的方法
     */
    @Override
    public void execute(NodeParameter parameter) {
        long beginTimestamp = System.currentTimeMillis();
        int stempJumpIndex = parameter.acceptStepJumpIndex();
        executeJump(parameter, stempJumpIndex);
        long runTime = System.currentTimeMillis() - beginTimestamp;
        parameter.addRunStatusMap(getMethod().getName(), runTime);
        LOGGER.info(getExecuteNode() + " with " + getMethod().getName() + " get execute time: {} ms ", runTime);
    }

    @Override
    public void executeJump(NodeParameter parameter, int stempJumpIndex) {
        if (stempJumpIndex == 0) {
            executeNoJump(parameter);
        }else {
            parameter.buildStepJumpIndex(parameter.acceptStepJumpIndex() - 1);
        }
    }

    @Override
    public void executeNoJump(NodeParameter parameter) {
        try {
            this.getMethod().invoke(getExecuteNode(), parameter);
        } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) {
            LOGGER.warn("无法找到该方法 {}", e.getMessage());
            try {
                this.getMethod().invoke(getExecuteNode());
            } catch (IllegalAccessException | InvocationTargetException e1) {
                throw new NotFoundMehtodOfClass("无法找到该方法" + getExecuteNode() + ":" + getMethod().getName(), e1);
            }

        }
    }

    @Override
    public void run(NodeParameter parameter, BlockingQueue<Method> methodQueue, BlockingQueue<CatenaNode> nodeQueue) {
        setMethod(methodQueue.peek());
        setExecuteNode(nodeQueue.peek());
        this.execute(parameter);
        if (this.getNextNode() != null) {
            if (methodQueue.size() != 1) {
                methodQueue.offer(methodQueue.poll());
            }
            if (nodeQueue.size() != 1) {
                nodeQueue.offer(nodeQueue.poll());
            }
            this.getNextNode().run(parameter, methodQueue, nodeQueue);
        }
    }

}
